package com.swak.telnet.cmd;

import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map.Entry;

import com.swak.utils.StringUtils;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

@Getter
@Setter
@Accessors(chain = true)
public class Options implements Iterable<Option> {
	private static Field HEAD = null;
	private static Field TAIL = null;
	static {
		try {
			HEAD = LinkedHashMap.class.getDeclaredField("head");
			HEAD.setAccessible(true);
			TAIL = LinkedHashMap.class.getDeclaredField("tail");
			TAIL.setAccessible(true);
		} catch (NoSuchFieldException | SecurityException e) {
		}
	}
	private LinkedHashMap<String, Option> map;

	public Options() {
		map = new LinkedHashMap<>();
	}

	public Options add(Option option) {
		map.put(option.getName(), option);
		return this;
	}

	@SuppressWarnings("unchecked")
	public Option first() {
		Entry<String, Option> entry;
		try {
			entry = (Entry<String, Option>) HEAD.get(map);
			return entry.getValue();
		} catch (IllegalArgumentException e) {
		} catch (IllegalAccessException e) {
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public Option last() {
		Entry<String, Option> entry;
		try {
			entry = (Entry<String, Option>) TAIL.get(map);
			return entry != null ? entry.getValue() : null;
		} catch (IllegalArgumentException e) {
		} catch (IllegalAccessException e) {
		}
		return null;
	}

	public Option get(String name) {
		return map.get(name);
	}

	@Override
	public Iterator<Option> iterator() {
		return map.values().iterator();
	}

	public Long getLong(String name) {
		Option option = map.get(name);
		if (option != null) {
			return option.getLong();
		}
		return null;
	}

	public Byte getByte(String name) {
		Option option = map.get(name);
		if (option != null) {
			return option.getByte();
		}
		return null;
	}

	public Boolean getBoolean(String name) {
		Option option = map.get(name);
		if (option != null) {
			return option.getBoolean();
		}
		return null;
	}

	public String getString(String name) {
		Option option = map.get(name);
		if (option != null) {
			return option.getString();
		}
		return null;
	}

	public Options addOption(String name, Object value) {
		this.add(Option.of(name, value));
		return this;
	}

	@Override
	public String toString() {
		StringBuilder cmd = new StringBuilder();
		for (Option option : this) {
			cmd.append(option.toString()).append(StringUtils.SPACE);
		}
		return cmd.toString();
	}
}
